/************************************************************************************************
 *   深圳市摩西尔电子有限公司 @版本所有@
 *
 *   此文件用于图像尺寸对齐，网口区域对齐
 *
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.9.7
 *      内容 : 所有代码
 *************************************************************************************************/

/* exported mc_card_pos */
/* exported mc_is_array */
/* exported mc_is_object */


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    图像尺寸对齐，网口区域对齐
 * 参数:
 *    @param { Promise<Array> } params 固定格式字符串
 *    @param { Promise<Boolean> } reset 重置网口;
 *                                     reset === true (若卡下无任何接收卡数据,将此卡当前的位置宽高设置为0); 并且直接将子集矩形赋值给父级
 *                                     reset === false 不处理传参数据; 并且将子集区域返回的矩形与父级矩形比较
 *    @param { Promise<boolean> } reset_port 重置网口-附加参数: 是否重置无接收卡的端口; 为true时置为0;
 * 返回:
 *    @returns { Promise<String> } params 返回矫正后的数据 || false
 * 例子:
 *    NA
 * 备注:
 *    注: 参数param每张卡数对象属性格式: { W, H, X, Y, CHILD (接收卡无该属性) }
 *
 *    1.以下 "DVI" 表示大屏;
 *    2.接收卡的位置是相对大屏位置(且接收卡在最内层为叶子节点,无子级); 其他的卡都是相对父级位置;
 *    3.该函数计算子级的最大矩阵与父级原始矩阵比较，若在父级之内则不改变父级；若超出父级；优先改变宽高后改变位置值；
 *    (第三步存在两种模式，具体参考参数说明); 已修改,请查看修改内容;
 *    4.计算之后需要将所有位置转化为相对父级位置；
 *    5.若卡下无任何接收卡数据 --> 将此卡当前的位置宽高设置为0(此时设置的是此卡的相对父级位置,还需要转化为大屏位置)
 *    6.卡数据对象添加是否支持截取参数 EN_IN_RECT: 判断是否支持截取；默认为true; 若为false时计算返回数据需要加上父级偏差值
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-09-07
 *       内容 : 所有代码
 *    2. 类型 : 修改
 *       作者 : 巫昭雯
 *       时间 : 2021-10-28
 *       内容 : 修改参数; 除数据参数数组外，只保留一个重置网口参数; 将原参数计算模式 mode 改为通过重置网口参数判断; 具体参照reset参数说明;
 *    3. 类型 : 添加
 *       作者 : 巫昭雯
 *       时间 : 2022-1-21
 *       内容 : 添加重置网口附加参数 reset_port
************************************************************************************************/
function mc_card_pos(params, reset, reset_port) {
    if (!mc_is_array(params) || "boolean" !== typeof reset || "boolean" !== typeof reset_port) {
        return false;
    }

    var init_len = params.length;

    if (0 > init_len) {
        return false;
    }

    // param fixed
    var cui_param_chi = "CHILD";
    // var cui_param_exist = "EXIST";
    // 是否支持截取
    var cui_param_in_rect = "EN_IN_RECT";

    // send card parent pos === DVI pos === big scree pos
    var obj_dvi = {
        X: 0,
        Y: 0,
        NAME: "DVI"
    };

    var obj_res = recur_calc_dvi_pos(params, obj_dvi);

    // deal send card offset xy
    add_parent_pos_for_output_port(params, obj_res.B_CHG);


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    递归换算成大屏位置 && 修改父级大小或位置(若需要) &&  转化为相对父级位置
     * 参数:
     *    @param { Promise<Array> } arr_chi params 参数的 CHILD 属性，子集集合数据；
     *    @param { Promise<Object> } parent_pos  父级位置数据(内含的位置值必须已转换的相对大屏的位置值)
     * 返回:
     *    @returns { Promise<Object> } RECT : 返回子集多个矩形 组成的矩形 ; B_CHG : 该项卡下的输出口数据需要修改
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-09-08
     *       内容 : 所有代码
    ************************************************************************************************/
    function recur_calc_dvi_pos(arr_chi, parent_pos) {
        var len = arr_chi.length;
        // 标记输出口是否需要加上父级卡位置
        var b_add_par_card_pos = false;

        for (var idx = 0; idx < len; idx++) {
            var item = arr_chi[idx];

            if (!mc_is_object(item)) {
                continue;
            }

            if (!item.CHILD) {
                // this is reseive card
                continue;
            }

            if (!mc_is_array(item.CHILD)) {
                continue;
            }

            // chg to relatively DVI data
            var obj_dvi_pos = {
                H: item.H ,
                W: item.W ,
                X: parent_pos.X + item.X,
                Y: parent_pos.Y + item.Y,
                NAME: item.NAME
            };

            if (false === item[cui_param_in_rect]) {
                b_add_par_card_pos = true;
            }

            var chi_len = item.CHILD.length;

            if (0 === chi_len) {
                // this is last level && no reseive card, so need to chang this item pos to relative DVI pos
                if (Object.prototype.hasOwnProperty.call(item, "X") && Object.prototype.hasOwnProperty.call(item, "Y")) {
                    if (reset && reset_port) {
                        // change current cardport rect to 0
                        item.X = 0;
                        item.Y = 0;
                        item.H = 0;
                        item.W = 0;
                    } else {
                        if (is_available_size(item)) {
                            // change position to relative DVI pos
                            item.X = parent_pos.X + item.X;
                            item.Y = parent_pos.Y + item.Y;
                        }
                    }
                }
                continue;
            }

            // 返回的可以包含子集的矩阵
            var res_chi = recur_calc_dvi_pos(item.CHILD, obj_dvi_pos);

            if (res_chi) {
                var res_rect = res_chi.RECT;

                if (res_rect) {
                    // 父级使用的矩形
                    var obj_parent_use_rect = {};

                    if (reset) {
                        // reset port data ; user child rect
                        obj_parent_use_rect = res_rect;
                    } else {
                        // 比较返回的矩形和父级原始矩形(已转化为相对大屏位置)
                        var res_judge = judge_two_rect(obj_dvi_pos, res_rect);

                        if (res_judge) {
                            obj_parent_use_rect = res_judge;
                        }
                    }

                    if (0 !== Object.keys(obj_parent_use_rect).length) {
                        // need to chg parent pos to relative DVI pos || size
                        item.W = obj_parent_use_rect.W;
                        item.H = obj_parent_use_rect.H;
                        item.X = obj_parent_use_rect.X;
                        item.Y = obj_parent_use_rect.Y;

                        // chg child to relative parent pos
                        modify_child_to_relative_parent_pos(item);

                        // add parent pos
                        add_parent_pos_for_output_port(item.CHILD, res_chi.B_CHG);
                    }
                }
            }
        }

        if ("DVI" === parent_pos.NAME) {
            return {
                B_CHG: b_add_par_card_pos
            };
        }

        return {
            B_CHG: b_add_par_card_pos,
            RECT: get_wrap_rect_from_grp_rect(arr_chi)
        };
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    获取一组多内多个矩形所能够容纳的外围矩形
     * 参数:
     *    @param { Promise<Array> } arr 多个矩形数据组成的数组
     * 返回:
     *    @returns { Promise<Boolean> } false === 参数错误 || 能够包裹多个卡的矩阵宽高和初始点位置 W,H,X,Y
     * 例子:
     *    NA
     * 备注:
     *    新增判断: 若矩形宽高为0; 则跳过;
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-09-08
     *       内容 : 所有代码
    ************************************************************************************************/
    function get_wrap_rect_from_grp_rect(arr) {
        if (!mc_is_array(arr)) {
            return false;
        }

        // defined
        var min_x = Math.pow(2, 53);
        var min_y = min_x;

        var max_x = 0;
        var max_y = 0;

        var len = arr.length;

        if (!len) {
            return false;
        }

        var ui_rx = 0;
        var ui_by = 0;

        for (var idx = 0; idx < len; idx++) {
            var obj_item = arr[idx];

            if (!mc_is_object(obj_item) || 0 === Object.keys(obj_item).length || 0 === obj_item.W || 0 === obj_item.H) {
                continue;
            }

            // set min
            if (obj_item.X < min_x) {
                min_x = obj_item.X;
            }

            if (obj_item.Y < min_y) {
                min_y = obj_item.Y;
            }

            // set  max
            ui_rx = obj_item.X + obj_item.W;

            if (max_x < ui_rx) {
                max_x = ui_rx;
            }

            ui_by = obj_item.Y + obj_item.H;

            if (max_y < ui_by) {
                max_y = ui_by;
            }
        }

        if (min_x === Math.pow(2, 53)) {
            return { X: 0, Y: 0, W: 0, H: 0 };
        }

        return {
            X: min_x,
            Y: min_y,
            W: max_x - min_x,
            H: max_y - min_y
        };
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    判断父矩形是包含子矩形
     * 参数:
     *    @param { Promise<Object> } parent_rect  父级矩形数据
     *    @param { Promise<Object> } chi_rect 子集矩形数据
     * 返回:
     *    @returns { Promise<Object> }  false === 已包含 || 需要修改的父级矩形数据宽高和初始点位置 W,H,X,Y
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-09-08
     *       内容 : 所有代码
    ************************************************************************************************/
    function judge_two_rect(parent_rect,chi_rect) {
        if (!mc_is_object(parent_rect) || !mc_is_object(chi_rect)) {
            return false;
        }

        // modify parent size
        if (parent_rect.W < chi_rect.W ) {
            parent_rect.W = chi_rect.W;
        }

        if (parent_rect.H < chi_rect.H) {
            parent_rect.H = chi_rect.H;
        }

        // X dir
        var jude_x = parent_rect.X <= chi_rect.X && (parent_rect.X + parent_rect.W) >= (chi_rect.X + chi_rect.W);

        // Y dir
        var jude_y = parent_rect.Y <= chi_rect.Y && (parent_rect.Y + parent_rect.H) >= (chi_rect.Y + chi_rect.H);

        if (jude_x && jude_y) {
            // maybe already modify size
            return parent_rect;
        }

        // modify pos === user child pos
        return {
            X: chi_rect.X,
            Y: chi_rect.Y,
            W: parent_rect.W,
            H: parent_rect.H
        };
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    修改子集内所有位置为相对父级位置
     * 参数:
     *    @param { Promise<String> } obj 带CHILD子集的父级数据对象 && param 该层的数据都是相对dvi的位置
     * 返回:
     *    @returns { Promise<Boolean> } 修改成功 || 传参错误
     * 例子:
     *    NA
     * 备注:
     *    该函数只修改一层数据，即一个父级和一个子集；其余数据不管
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-09-08
     *       内容 : 所有代码
    ************************************************************************************************/
    function modify_child_to_relative_parent_pos(obj) {
        if (!mc_is_object(obj)) {
            return false;
        }

        var u_p_x = obj.X;
        var u_p_y = obj.Y;
        var arr_chi = obj[cui_param_chi];

        if (!mc_is_array(arr_chi)) {
            return false;
        }

        var len = arr_chi.length;

        for (var idx = 0; idx < len; idx++) {
            var item_chi = arr_chi[idx];

            if (!mc_is_object(item_chi)) {
                continue;
            }

            if (Object.prototype.hasOwnProperty.call(item_chi, "X") && Object.prototype.hasOwnProperty.call(item_chi, "Y")) {
                if (0 === item_chi.W || 0 === item_chi.H) {
                    continue;
                }

                item_chi.X -= u_p_x;
                item_chi.Y -= u_p_y;
            }
        }

        return true;
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    给输出口添加父级卡位置; 只有在参数卡属性值 "EN_IN_RECT" === false 时修改
     * 参数:
     *    @param { Promise<Array> } arr_card 当前项为卡的数据数组; hub卡 || send卡
     *    @param { Promise<Boolean> } b_chg 修改子级输出口位置; true === 需要修改
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-02-05
     *       内容 : 所有代码
    ************************************************************************************************/
    function add_parent_pos_for_output_port(arr_card, b_chg) {
        if (!b_chg || !mc_is_array(arr_card)) {
            return;
        }

        var ui_len = arr_card.length;

        for (var ui_i = 0; ui_i < ui_len; ui_i++) {
            var item = arr_card[ui_i];

            if (!mc_is_object(item)) {
                continue;
            }

            if (!Object.prototype.hasOwnProperty.call(item, cui_param_in_rect)) {
                continue;
            }

            if (true === item[cui_param_in_rect]) {
                continue;
            }

            if (!is_available_size(item)) {
                continue;
            }

            if (0 === item.X && 0 === item.Y) {
                continue;
            }

            add_parent_pos(item.CHILD, item.X, item.Y);
        }


        /************************************************************************************************
         * 类型:
         *    函数
         * 功能:
         *    输出口对象添加父级位置
         * 参数:
         *    @param { Promise<Array> } a_chi 子级数据; 为卡输出口数据
         *    @param { Promise<Number> } ui_x 父级卡位置偏差值 X
         *    @param { Promise<Number> } ui_y 父级卡位置偏差值 Y
         * 返回:
         *    NA
         * 例子:
         *    NA
         * 备注:
         *    NA
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2021-02-05
         *       内容 : 所有代码
        ************************************************************************************************/
        function add_parent_pos(a_chi, ui_x, ui_y) {
            if (!a_chi) {
                return;
            }
            var ui_len_chi = a_chi.length;

            if (0 === ui_len_chi) {
                return;
            }

            for (var ui_chi_i = 0; ui_chi_i < ui_len_chi; ui_chi_i++) {
                var obj_i = a_chi[ui_chi_i];

                if (!is_available_size(obj_i)) {
                    continue;
                }

                obj_i.X += ui_x;
                obj_i.Y += ui_y;
            }
        }
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    判断单项数据对象是否为可用的大小; 即宽高不为0
     * 参数:
     *    @param { Promise<Object> } obj 单项数据对象
     * 返回:
     *    @returns { Promise<Boolean> } true === 可用(宽或高不为0) || false === 不可用
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-02-05
     *       内容 : 所有代码
    ************************************************************************************************/
    function is_available_size(obj) {
        if ("object" !== typeof obj) {
            return false;
        }

        if (Object.prototype.hasOwnProperty.call(obj, "W") && Object.prototype.hasOwnProperty.call(obj, "H")) {
            if (0 === obj.W || 0 === obj.H) {
                return false;
            }

            return true;
        }

        return false;
    }


    return params;
}


function mc_is_array(arr) {
    if (arr) {
        return (arr.constructor === Array);
    }

    return false;
}


function mc_is_object(obj) {
    if (obj) {
        return (obj.constructor === Object);
    }

    return false;
}


